package org.csu.demo.nettydemo.netty;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import org.csu.demo.nettydemo.domain.User;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

//业务逻辑处理
public class WebSocketTextHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 文件传输上下文定义（放在类开头）
    private static final AttributeKey<FileTransferContext> FILE_TRANSFER_CTX =
            AttributeKey.valueOf("fileTransferCtx");

    private static class FileTransferContext {
        String fileName;
        CompositeByteBuf buffer; // 使用CompositeByteBuf
        long receivedSize;
        long expectedSize;       // 添加expectedSize字段
    }

    // 处理二进制帧（修正addComponent用法）
    private void handleBinaryFrame(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) {
        FileTransferContext context = ctx.channel().attr(FILE_TRANSFER_CTX).get();
        if (context == null) {
            System.err.println("错误：未收到文件元数据，丢弃分片");
            frame.content().release();
            return;
        }

        ByteBuf content = frame.content();
        if (context.buffer == null) {
            context.buffer = ctx.alloc().compositeBuffer();
        }
        content.retain();
        context.buffer.addComponent(true, content);
        context.receivedSize += content.readableBytes();

        System.out.printf("收到分片：%d/%d 字节，文件：%s\n",
                context.receivedSize,
                context.expectedSize,
                context.fileName
        );

        // 检查是否接收完成
        if (context.receivedSize >= context.expectedSize) {
            System.out.println("文件接收完成，开始转发...");
            forwardFileToGroup(ctx, context);
            cleanupTransferContext(ctx);
        }
    }

    // 清理传输上下文
    private void cleanupTransferContext(ChannelHandlerContext ctx) {
        FileTransferContext context = ctx.channel().attr(FILE_TRANSFER_CTX).getAndSet(null);
        if (context != null && context.buffer != null) {
            context.buffer.release();
        }
    }

    // 实现forwardFileToGroup方法（新增）
    private void forwardFileToGroup(ChannelHandlerContext ctx, FileTransferContext context) {
        SocketSession session = SocketSession.getSession(ctx);
        if (session == null || context.buffer == null) return;

        String group = session.getGroup();
        ChannelGroup channelGroup = SessionGroup.inst().getGroup(group);

        if (channelGroup != null) {
            // 1. 发送元数据
            Map<String, String> meta = new HashMap<>();
            meta.put("type", "file_forward");
            meta.put("fileName", context.fileName);
            meta.put("fileSize", String.valueOf(context.expectedSize));
            meta.put("sendUser", session.getUser().getNickname());
            meta.put("group", group); // 确保包含群组信息
            String jsonMeta = new Gson().toJson(meta);
            String metaWithHeader = addHeader(jsonMeta);
            ChannelGroupFuture metaFuture = channelGroup.writeAndFlush(new TextWebSocketFrame(metaWithHeader));
            metaFuture.addListener(future -> {
                if (future.isSuccess()) {
                    System.out.println("文件元数据发送成功");
                } else {
                    System.err.println("文件元数据发送失败: " + future.cause().getMessage());
                }
            });

            // 2. 发送二进制数据
            ChannelGroupFuture dataFuture = channelGroup.writeAndFlush(new BinaryWebSocketFrame(context.buffer.retainedDuplicate()));
            dataFuture.addListener(future -> {
                if (future.isSuccess()) {
                    System.out.println("文件二进制数据发送成功");
                } else {
                    System.err.println("文件二进制数据发送失败: " + future.cause().getMessage());
                }
            });
        }

        cleanupTransferContext(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof BinaryWebSocketFrame) {
            handleBinaryFrame(ctx, (BinaryWebSocketFrame) msg);
        } else {
            super.channelRead(ctx, msg);
        }
    }

    // 修改 addHeader 方法（使用Base64编码避免特殊字符问题）
    private String addHeader(String message) {
        int type = 1;
        String encoded = Base64.getEncoder().encodeToString(message.getBytes(StandardCharsets.UTF_8));
        return type + "|" + encoded.length() + "|" + encoded;
    }

    // 修改 parseHeader 方法
    private Map<String, Object> parseHeader(TextWebSocketFrame frame) {
        try {
            String text = frame.text();
            String[] parts = text.split("\\|", 3); // 使用 | 分割更可靠
            if (parts.length != 3) {
                throw new IllegalArgumentException("Invalid message format");
            }

            byte[] decoded = Base64.getDecoder().decode(parts[2]);
            String message = new String(decoded, StandardCharsets.UTF_8);

            Map<String, Object> result = new HashMap<>();
            result.put("type", Integer.parseInt(parts[0]));
            result.put("length", Integer.parseInt(parts[1]));
            result.put("message", message);
            return result;
        } catch (Exception e) {
            System.err.println("解析包头时出现异常: " + e.getMessage());
            return null;
        }
    }

    // 新增：连接建立时初始化人数（在userEventTriggered中追加）
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

        // 是否握手成功，升级为 Websocket 协议
        if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {
            // 握手成功，移除 HttpRequestHandler，因此将不会接收到任何消息
            // 并把握手成功的 Channel 加入到 ChannelGroup 中
            new SocketSession(ctx.channel());

            // 新增：主动发送当前群组人数给新用户
            SocketSession session = SocketSession.getSession(ctx);
            if (session != null && session.getGroup() != null) {
                Map<String, String> initMsg = new HashMap<>();
                initMsg.put("type", "online");
                initMsg.put("group", session.getGroup());
                initMsg.put("count", String.valueOf(SessionGroup.inst().getGroupOnline(session.getGroup())));
                String json = new Gson().toJson(initMsg);
                String messageWithHeader = addHeader(json);
                ctx.writeAndFlush(new TextWebSocketFrame(messageWithHeader));
            }
        }
        //读空闲事件，60s无消息
        else if (evt instanceof IdleStateEvent) {
            IdleStateEvent stateEvent = (IdleStateEvent) evt;
            if (stateEvent.state() == IdleState.READER_IDLE) {
                System.out.println("长时间不发送消息");
                //正常应关闭通道
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        try {
            Map<String, Object> headerInfo = parseHeader(textWebSocketFrame);
            if (headerInfo == null) {
                return;
            }
            int type = (int) headerInfo.get("type");
            int length = (int) headerInfo.get("length");
            String message = (String) headerInfo.get("message");

            SocketSession session = SocketSession.getSession(channelHandlerContext);
            if (session == null) {
                System.err.println("SocketSession 对象为 null");
                return;
            }

            if (message == null || message.isEmpty()) {
                System.err.println("接收到的消息为空");
                return;
            }

            TypeToken<HashMap<String, String>> typeToken = new TypeToken<HashMap<String, String>>() {};
            Gson gson = new Gson();
            java.util.Map<String, String> map = gson.fromJson(message, typeToken.getType());
            User user = null;
            System.out.println("接收到的消息: " + map); // 添加日志输出
            switch (map.get("type")) {
                case "msg":
                    Map<String, String> result = new HashMap<>();
                    user = session.getUser();
                    if (user == null) {
                        System.err.println("User 对象为 null");
                        break;
                    }
                    result.put("type", "msg");
                    result.put("msg", map.get("msg"));
                    result.put("sendUser", user.getNickname());
                    result.put("group", session.getGroup()); // 添加群组信息
                    System.out.println("准备发送给其他成员的消息: " + result); // 添加日志输出

                    // 发送给组内其他成员（排除自己）
                    sendMessage(channelHandlerContext, result);
                    break;
                case "init": // 初始化会话（用户加入）
                    String room = map.get("room");
                    session.setGroup(room);
                    String nick = map.get("nick");
                    user = new User(session.getSessionId(), nick);
                    session.setUser(user);
                    SessionGroup.inst().addSession(session);
                    SessionGroup.inst().sendEnterNotice(session, "进入了群");
                    break;
                case "ping": // 处理心跳请求,每30s发送一次，以保持连接
                    Map<String, String> pong = new HashMap<>();
                    pong.put("type", "pong");
                    String jsonPong = new Gson().toJson(pong);
                    String pongWithHeader = addHeader(jsonPong);
                    channelHandlerContext.writeAndFlush(new TextWebSocketFrame(pongWithHeader));
                    //System.out.println("心跳了");注释掉取消打印
                    break;
                case "switch": // 新增：处理用户切换聊天室的请求
                    String newGroup = map.get("room");
                    SessionGroup.inst().switchSession(session, newGroup);
                    break;
                case "image": // 新增：处理图片消息
                    Map<String, String> imageResult = new HashMap<>();
                    user = session.getUser();
                    if (user == null) {
                        System.err.println("User 对象为 null");
                        break;
                    }
                    imageResult.put("type", "image");
                    imageResult.put("msg", map.get("msg"));
                    imageResult.put("sendUser", user.getNickname());
                    imageResult.put("group", session.getGroup()); // 添加群组信息
                    System.out.println("准备发送给其他成员的图片消息: " + imageResult); // 添加日志输出

                    // 发送给组内其他成员（排除自己）
                    sendMessage(channelHandlerContext, imageResult);
                    break;
                case "file": // 新增：处理文件消息
                    Map<String, String> fileResult = new HashMap<>();
                    user = session.getUser();
                    if (user == null) {
                        System.err.println("User 对象为 null");
                        break;
                    }
                    fileResult.put("type", "file");
                    fileResult.put("msg", map.get("msg"));
                    fileResult.put("sendUser", user.getNickname());
                    fileResult.put("group", session.getGroup());
                    fileResult.put("fileName", map.get("fileName")); // 添加文件名信息
                    System.out.println("准备发送给其他成员的文件消息: " + fileResult);

                    // 发送给组内其他成员（排除自己）
                    sendMessage(channelHandlerContext, fileResult);
                    break;
                case "file_meta":
                    FileTransferContext context = new FileTransferContext();
                    context.fileName = map.get("fileName"); // 字段名必须匹配
                    context.expectedSize = Long.parseLong(map.get("fileSize")); // 字段名必须匹配
                    channelHandlerContext.channel().attr(FILE_TRANSFER_CTX).set(context);
                    break;
            }
        } catch (Exception e) {
            // 记录完整的异常堆栈信息
            System.err.println("处理消息时出现异常: ");
            e.printStackTrace();
        }
    }

    // 新增：断开时打印人数（在channelInactive中追加）
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        SocketSession session = SocketSession.getSession(ctx);
        if (session != null && session.isValid()) {
            // 改为在closeSession的监听器中打印日志（异步回调）
            SessionGroup.inst().closeSession(session, "退出通知"); // 调用带echo的版本
        }
        super.channelInactive(ctx);
    }

    // 修改发送消息的逻辑，添加包头
    private void sendMessage(ChannelHandlerContext ctx, Map<String, String> result) {
        SocketSession session = SocketSession.getSession(ctx);
        if (session == null) {
            System.err.println("发送消息时获取不到Session");
            return;
        }

        // 调试信息
        System.out.println("准备通过SessionGroup发送消息: " + result);

        // 使用SessionGroup的群发方法
        SessionGroup.inst().sendToOthers(result, session);

        /*// 同时保留原发送逻辑给自己回显（可选）
        String jsonMessage = new Gson().toJson(result);
        String messageWithHeader = addHeader(jsonMessage);
        ctx.writeAndFlush(new TextWebSocketFrame(messageWithHeader));*/
    }
}